﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace TTUnityPlugin {
/// <summary>
/// Loader 父类
/// </summary>
public abstract class AssetBundleLoader {
     internal AssetBundleManager.LoadAssetCompleteHandler onComplete;
//
//     public string bundleName;
     public bool loadAsync;
//     public AssetBundleData bundleData;
     public AssetBundleInfo bundleInfo;
     public AssetBundleManager bundleManager;
     public LoadState state = LoadState.State_None;
     public AssetBundleLoader[] depLoaders;

    public AssetBundleLoader() {
        loadAsync = false;
    }

    public AssetBundleLoader(bool async) {
        this.loadAsync = async;
    }

    public virtual void Load() {

    }

    /// <summary>
    /// 其它都准备好了，加载AssetBundle
    /// 注意：这个方法只能被 AssetBundleManager 调用
    /// 由 Manager 统一分配加载时机，防止加载过卡
    /// </summary>
    public virtual void LoadBundle() {

    }

    public abstract Object LoadAsset(string name);

    public virtual bool isComplete {
        get {
            return state == LoadState.State_Error || state == LoadState.State_Complete;
        }
    }

    protected virtual void Complete() {
        if(onComplete != null) {
            var handler = onComplete;
            onComplete = null;
            handler(bundleInfo);
        }
//         UIImageCache.getInstance().AddAtlasCache(bundleInfo);
//         bundleManager.LoadComplete(this);
    }

    protected virtual void Error() {
        if(onComplete != null) {
            var handler = onComplete;
            onComplete = null;
            handler(bundleInfo);
        }
        //bundleManager.LoadError(this);
    }
}

/// <summary>
/// 在手机运行时加载
/// </summary>
public class MobileAssetBundleLoader : AssetBundleLoader {
    protected int _currentLoadingDepCount;
    protected AssetBundle _bundle;
    protected bool _hasError;

    public MobileAssetBundleLoader(bool async) {
        loadAsync = async;
    }

    /// <summary>
    /// 开始加载
    /// </summary>
    override public void Load() {
        if(_hasError)
            state = LoadState.State_Error;

        if(state == LoadState.State_None) {
            state = LoadState.State_Loading;

            this.LoadDepends();
        } else if(state == LoadState.State_Error) {
            this.Error();
        } else if(state == LoadState.State_Complete) {
            this.Complete();
        }
    }

    public override Object LoadAsset(string name) {
//         if(bundleInfo == null) {
//             PluginLog.LogWarningFormat("Load asset {0} faild!", name);
//         }
//         return bundleInfo.LoadObject(name);
        return null;
    }

     void LoadDepends() {
//         if(bundleData.existDependencies.Length == 0) {
//             _currentLoadingDepCount = 0;
//             this.CheckDepComplete();
//             return;
//         }
//
//         if(depLoaders == null) {
//             depLoaders = new AssetBundleLoader[bundleData.existDependencies.Length];
//             for (int i = 0; i < bundleData.existDependencies.Length; i++)
//             {
//                 depLoaders[i] = bundleManager.CreateLoader(bundleData.existDependencies[i], this.loadAsync, null);
//             }
//         }
//
//         _currentLoadingDepCount = depLoaders.Length;
//         for(int i = 0; i < depLoaders.Length; i++) {
//             AssetBundleLoader depLoader = depLoaders[i];
//             if(!depLoader.isComplete) {
//                 depLoader.onComplete += OnDepComplete;
//                 depLoader.Load();
//             } else {
//                 _currentLoadingDepCount--;
//             }
//         }
//         this.CheckDepComplete();
    }

    /// <summary>
    /// 其它都准备好了，加载AssetBundle
    /// 注意：这个方法只能被 AssetBundleManager 调用
    /// 由 Manager 统一分配加载时机，防止加载过卡
    /// </summary>
    override public void LoadBundle() {
//         if(loadAsync) {
//             bundleManager.StartCoroutine(LoadFromFileAsync());
//         } else {
//             LoadFile();
//         }
    }


    protected virtual void LoadFile() {
//         if(state != LoadState.State_Error)
//         {
//
// #if UNITY_5_3_OR_NEWER
//                 _bundle = AssetBundle.LoadFromFile(bundleData.fullUir);
// #else
//                 _bundle = AssetBundle.CreateFromFile(bundleData.fullUir);
// #endif
//                 this.Complete();
//         }
//     }
//         protected virtual IEnumerator LoadFromFileAsync()
//         {
//             if(state != LoadState.State_Error)
//             {
//     #if UNITY_5_3_OR_NEWER
//                     AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(bundleData.fullUir);
//                     yield return request;
//                     _bundle = request.assetBundle;
//     #else
//                     _bundle = AssetBundle.CreateFromFile(bundleData.fullUir);
//     #endif
//                     this.Complete();
//
//             }
        }

    void OnDepComplete(AssetBundleInfo abi) {
        _currentLoadingDepCount--;
        this.CheckDepComplete();
    }

    void CheckDepComplete() {
//         if(_currentLoadingDepCount == 0) {
//             bundleManager.RequestLoadBundle(this);
//         }
    }

    override protected void Complete() {
//         if(bundleInfo == null) {
//             this.state = LoadState.State_Complete;
//
//             this.bundleInfo = bundleManager.CreateBundleInfo(this, null, _bundle);
//             this.bundleInfo.isReady = true;
//             this.bundleInfo.onUnloaded = OnBundleUnload;
//             if(depLoaders != null)
//                 foreach(AssetBundleLoader depLoader in depLoaders) {
//                     bundleInfo.AddDependency(depLoader.bundleInfo);
//                 }
//
//             _bundle = null;
//         }
//         base.Complete();
    }

    private void OnBundleUnload(AssetBundleInfo abi) {
        this.bundleInfo = null;
        this.state = LoadState.State_None;
    }

    override protected void Error() {
        _hasError = true;
        this.state = LoadState.State_Error;
        this.bundleInfo = null;
        base.Error();
    }
}
public class BuiltInResLoader : AssetBundleLoader {
    public Object _object;
    private static Stack<BuiltInResLoader> loaders = new Stack<BuiltInResLoader>();
    public string resName;

    public override void Load() {
//         this.state = LoadState.State_Loading;
//         if(loadAsync) {
//             bundleManager.StartCoroutine(LoadResAsync());
//         } else {
//             LoadRes();
//         }
    }

    private void LoadRes() {
#if UNITY_EDITOR
        // load ui res in editor
        if(resName.ToLower().StartsWith("assets/resources/")) {
            _object = UnityEditor.AssetDatabase.LoadAssetAtPath(resName, typeof(UnityEngine.Object));
            if(_object == null) {
                this.Error();
            } else {
                this.Complete();
            }
            return;
        }
#endif
        string resourceLoadPath = resName.ToLower();
        int start = resourceLoadPath.IndexOf("resources/") + 10;
        int end = resourceLoadPath.LastIndexOf(".");
        resourceLoadPath = resourceLoadPath.Substring(start, end > 0 ? end - start : resourceLoadPath.Length - start);
#if UNITY_EDITOR
        if(string.IsNullOrEmpty(resourceLoadPath)) {
            Debug.LogError("[ABLoader] respath string is empty");
        }
#endif
        // find really resource path
        _object = Resources.Load(resourceLoadPath, typeof(UnityEngine.Object));
        if(_object == null) {
            this.Error();
        } else {
            this.Complete();
        }
    }

    private IEnumerator LoadResAsync() {
// #if UNITY_EDITOR
//         // load ui res in editor
//         LTGame.DebugUtil.Log("LoadResAsync " + resName + " start!");
//         if(resName.ToLower().StartsWith("assets/resources/")) {
//             _object = UnityEditor.AssetDatabase.LoadAssetAtPath(resName, typeof(UnityEngine.Object));
//             LTGame.DebugUtil.Log("LoadResAsync " + resName + "yield end!");
//             yield return null;
//             if(_object == null) {
//                 this.Error();
//             } else {
//                 this.Complete();
//                 LTGame.DebugUtil.Log("LoadResAsync " + resName + " End!");
//             }
//             yield break;
//         }
// #endif
//         string resourceLoadPath = resName.ToLower();
//         int start = resourceLoadPath.IndexOf("resources/") + 10;
//         int end = resourceLoadPath.LastIndexOf(".");
//         resourceLoadPath = resourceLoadPath.Substring(start, end > 0 ? end - start : resourceLoadPath.Length - start);
// #if UNITY_EDITOR
//         if(string.IsNullOrEmpty(resourceLoadPath)) {
//             Debug.LogError("[ABLoader] respath string is empty");
//         }
// #endif
//         // find really resource path
//         ResourceRequest request = Resources.LoadAsync(resourceLoadPath, typeof(UnityEngine.Object));
//         yield return request;
//         if(request.isDone) {
//             _object = request.asset;
//         }
//         if(_object == null) {
//             this.Error();
//         } else {
//             this.Complete();
//         }

        yield break;
    }

    public override Object LoadAsset(string name) {
        return _object;
    }

    protected override void Complete() {
        this.state = LoadState.State_Complete;
        if(onComplete != null) {
            var handler = onComplete;
            onComplete = null;
            handler(bundleInfo);
        }
    }

    protected override void Error() {
        this.state = LoadState.State_Error;
        if(onComplete != null) {
            var handler = onComplete;
            onComplete = null;
            handler(bundleInfo);
        }
    }

    private BuiltInResLoader(bool async) {
//         loadAsync = async;
//         this.bundleInfo = new BuiltInResInfo(this);
//         this.Complete();
    }

    public static BuiltInResLoader GetLoader(bool async = false) {
        if(loaders.Count > 0) {
            BuiltInResLoader loader =  loaders.Pop();
            loader.loadAsync = async;
            return loader;
        }
        return new BuiltInResLoader(async);
    }

    public static void ReleaseLoader(BuiltInResLoader loader) {
        loader._object = null;
        loader.resName = null;
        loaders.Push(loader);
    }
}
}
